﻿<!doctype HTML>
<html>
<head>
    <script>
        // Set variables

        // Get URL parameters:
        // `code` contains the code of the file in base64 encoded
        // `theme` can be "vs" for light theme or "vs-dark" for dark theme
        // `lang` is the language of the file
        // `wrap` if the editor is wrapping or not
        // `minimap` if the minimap is shown
        // `contextMenu` whether to use the Monaco context menu. The built-in context menu
        //               doesn't work in Peek, so we set this to false and create a custom one

        var theme = ("[[PT_THEME]]" == "dark") ? "vs-dark" : "vs";
        var wrap = [[PT_WRAP]];
        var minimap = [[PT_MINIMAP]];
        var stickyScroll = [[PT_STICKY_SCROLL]];
        var fontSize = [[PT_FONT_SIZE]];
        
        var lang = "[[PT_LANG]]";
        var base64code = "[[PT_CODE]]";
        var contextMenu = [[PT_CONTEXTMENU]];

        var editor;

        // Code taken from https://stackoverflow.com/a/30106551/14774889
        var code = decodeURIComponent(atob(base64code).split('').map(function (c) {
            return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
        }).join(''));

        function runToggleTextWrapCommand() {
            wrap = !wrap;
            editor.updateOptions({ wordWrap: wrap ? 'on' : 'off' });
        }

        function runToggleMinimap() {
            minimap = !minimap;
            editor.updateOptions({minimap: {enabled: minimap}});
        }

        function runCopyCommand() {
            editor.focus();
            document.execCommand('copy');
        }

    </script>
    <!-- Set browser to Edge-->
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <!-- Set charset -->
    <meta charset="utf-8" />
    <!-- Title (normally not displayed)-->
    <title>Previewer for developer Files</title>
    <style>
        /* Fits content to window size */
        html, body {
            padding: 0;
        }

        #container, .monaco-editor {
            position: fixed;
            height: 100%;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
        }

        .overflowingContentWidgets {
            /*Hides alert box */
            display: none !important
        }
    </style>
</head>

<body>
    <!-- Container for the editor -->
    <div id="container"></div>
    <!-- Script -->
    <script src="http://[[PT_URL]]/monacoSRC/min/vs/loader.js"></script>
    <script src="http://[[PT_URL]]/monacoSpecialLanguages.js" type="module"></script>
    <script type="module">
        import { registerAdditionalLanguages } from 'http://[[PT_URL]]/monacoSpecialLanguages.js';
        import { customTokenThemeRules } from 'http://[[PT_URL]]/customTokenThemeRules.js';
        require.config({ paths: { vs: 'http://[[PT_URL]]/monacoSRC/min/vs' } });
        require(['vs/editor/editor.main'], async function () {
            await registerAdditionalLanguages(monaco)

            // Creates a theme to handle custom tokens
            monaco.editor.defineTheme('theme', {
                base: theme, // Sets the base theme to "vs" or "vs-dark" depending on the user's preference
                inherit: true,
                rules: customTokenThemeRules,
                colors: {} // `colors` is a required attribute
            });

            // Creates the editor
            // For all parameters: https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html
            editor = monaco.editor.create(document.getElementById('container'), {
                value: code, // Sets content of the editor
                language: lang, // Sets language of the code
                readOnly: true, // Sets to readonly
                theme: 'theme', // Sets editor theme
                minimap: { enabled: minimap }, // Controls if minimap is shown
                lineNumbersMinChars: 3, // Width of the line numbers
                contextmenu: contextMenu,
                scrollbar: {
                    // Deactivate shadows
                    shadows: false,

                    // Render scrollbar automatically
                    vertical: 'auto',
                    horizontal: 'auto',
                },
                stickyScroll: { enabled: stickyScroll },
                fontSize: fontSize,
                wordWrap: (wrap ? 'on' : 'off') // Word wraps
            });
            window.onresize = () => {
                editor.layout();
            };

            // Add toggle wrap button to context menu
            editor.addAction({
                id: 'text-wrap',

                label: 'Toggle text wrapping',

                // A precondition for this action.
                precondition: null,

                // A rule to evaluate on top of the precondition in order to dispatch the keybindings.
                keybindingContext: null,

                contextMenuGroupId: 'cutcopypaste',

                contextMenuOrder: 100,

                // Method that will be executed when the action is triggered.
                run: runToggleTextWrapCommand
            });

            editor.addAction({
                id: 'toggle-minimap',

                label: 'Toggle minimap',

                contextMenuGroupId: 'cutcopypaste',

                contextMenuOrder: 100,

                // Method that will be executed when the action is triggered.
                run: runToggleMinimap
            });

            onContextMenu();
        });

        function onContextMenu() {
            // Hide context menu items
            // Code modified from https://stackoverflow.com/questions/48745208/disable-cut-and-copy-in-context-menu-in-monaco-editor/65413517#65413517
            let menus = require('vs/platform/actions/common/actions').MenuRegistry._menuItems
            let contextMenuEntry = [...menus].find(entry => entry[0].id == 'EditorContext')
            let contextMenuLinks = contextMenuEntry[1]

            let removableIds = ['editor.action.clipboardCutAction', 'editor.action.formatDocument', 'editor.action.formatSelection', 'editor.action.quickCommand', 'editor.action.quickOutline', 'editor.action.refactor', 'editor.action.sourceAction', 'editor.action.rename', undefined, 'editor.action.revealDefinition', 'editor.action.revealDeclaration', 'editor.action.goToTypeDefinition', 'editor.action.goToImplementation', 'editor.action.goToReferences', 'editor.action.changeAll']

            let removeById = (list, ids) => {
                let node = list._first
                do {
                    if (node.element == undefined) break;
                    let shouldRemove = ids.includes(node.element?.command?.id)
                    if (shouldRemove) { list._remove(node) }
                } while ((node = node.next))
            }

            removeById(contextMenuLinks, removableIds)
        }
    </script>
</body>
</html>